import numpy as np

import datetime
#from mscf.fc3.project.volfitter.analytics.volsurfacefitter import VolSurfaceFitter
#import VolSurfaceFitter
import math

STRIKE_BY_SPOT_LOWER_BOUND = 0.6
STRIKE_BY_SPOT_UPPER_BOUND = 1.2
NUMBER_OF_DISCRETIZED_STRIKES = 100

NUM_SECONDS_IN_YEAR = 365 * 24 * 60 * 60

class DTM:
    def __init__(self, expDate, term):
        self.term = term
        self.expDate = expDate

class ParametricVolSurface:

    def __init__(self,  refSpot = None, mMatrix = None, rInterest=None, terms = None, dtms = None):
        self.refSpot = refSpot
        self.mMatrix = mMatrix
#        self.parameters = parameters

        strikeLowerBound = refSpot * STRIKE_BY_SPOT_LOWER_BOUND
        strikeUpperBound = refSpot * STRIKE_BY_SPOT_UPPER_BOUND
        strikeSpacing = (strikeUpperBound - strikeLowerBound) / NUMBER_OF_DISCRETIZED_STRIKES
        strikes = np.arange(strikeLowerBound, strikeUpperBound, strikeSpacing )

        self.strikes = strikes
        self.dtms = dtms
        self.createDtmMap()
        self.terms = terms
        self.r=rInterest

    def createDtmMap(self):
        self.dtmMap = dict()
        for dtm in self.dtms:
            self.dtmMap[dtm.expDate]=dtm.term

    def lookupVolatility(self, strike, term):

        #use parameters and qfit to find neighboring implied vols
        # and linear interpolate after that

        #Find Term_i<term<Term_i+1
        #Calculate Vol

        lowIndex=0
        highIndex=1

        #do not consider extrapolation in this code
        volCurveCount=len(self.mMatrix)

        ##        print "lowest term  " + str(self.mMatrix[0][0])
        ##        print "highest term  " + str(self.mMatrix[volCurveCount-1][0])

        print volCurveCount
        if self.mMatrix[0][0]>term or self.mMatrix[volCurveCount-1][0]<term:
            print "lowest term" + str(self.mMatrix[0][0])
            print "highest term" + str(self.mMatrix[volCurveCount-1][0])
            return 0.3

        for i in range(volCurveCount-1):
            if self.mMatrix[i][0]<term and self.mMatrix[i+1][0]>=term:
                lowIndex=i
                highIndex=+1
                break


        S=self.mMatrix[lowIndex][1]
        r=self.mMatrix[lowIndex][2]

        #paramsWithVatm=[T,S,r,Vatm, parameters[0],parameters[1],parameters[2] ]
        #Vol with same strike lower term
        lowTerm=self.mMatrix[lowIndex][0]
        F = S * math.exp(r * lowTerm)
        Vatm=self.mMatrix[lowIndex][3]
        m1=math.log(strike/F)/(Vatm*math.sqrt(lowTerm))
        m2=m1*m1;
        vol_low=self.mMatrix[lowIndex][4]+self.mMatrix[lowIndex][5]*m1+self.mMatrix[lowIndex][6]*m2

        #Vol with same strike higher term
        highTerm=self.mMatrix[highIndex][0]
        F = S * math.exp(r * highTerm)
        Vatm=self.mMatrix[highIndex][3]
        m1=math.log(strike/F)/(Vatm*math.sqrt(highTerm))
        m2=m1*m1;
        vol_high=self.mMatrix[highIndex][4]+self.mMatrix[highIndex][5]*m1+self.mMatrix[highIndex][6]*m2

        ##        print vol_low
        ##        print vol_high
        vol=vol_low*(highTerm-term)/(highTerm-lowTerm)+vol_high*(term-lowTerm)/(highTerm-lowTerm)

        #print vol                


        return vol[0,0]



    def getDiscretizedXYZTuples(self):

        kByS = [K / self.refSpot for K in self.strikes]

        kBySGrid, termGrid = np.meshgrid(kByS, self.terms)

        volGrid = [[self.lookupVolatility(K, T) for K in self.strikes] for T in self.terms]

        volGridArray = np.asarray(volGrid)

        return kBySGrid, termGrid, volGridArray


#        return self.getTestXYZData(0.05)

    @staticmethod
    def getTestXYZData(delta=0.05):
        '''
        Return a tuple X, Y, Z with a test data set.
        '''

        from matplotlib.mlab import  bivariate_normal
        x = y = np.arange(-3.0, 3.0, delta)
        X, Y = np.meshgrid(x, y)

        Z1 = bivariate_normal(X, Y, 1.0, 1.0, 0.0, 0.0)
        Z2 = bivariate_normal(X, Y, 1.5, 0.5, 1, 1)
        Z = Z2 - Z1

        X *= 10
        Y *= 10
        Z *= 500
        return X, Y, Z


    def getDiscretizedXYTuples(self, expirationDate):

        term = self.dtmMap[expirationDate]

        kBySArray = [K / self.refSpot for K in self.strikes]

        volArray = [self.lookupVolatility(K, term) for K in self.strikes]

        return kBySArray, volArray

#        return self.getTestXYData()

    @staticmethod
    def getTestXYData():
        X = np.linspace(0,2*np.pi,50)
        Y = np.sin(X)
        return X, Y
